package component

import (
	"database/sql"
	"time"

	"gitee.com/chenhonghua/ginorigin/config/http/restful"
	"gitee.com/chenhonghua/ginorigin/config/http/router"
	"gitee.com/chenhonghua/ginorigin/config/storage/database"
	"gitee.com/chenhonghua/ginorigin/config/system/zap"

	"github.com/gin-gonic/gin"
	"gorm.io/gorm"
)

type componentDatabaseDemo struct{}

func (d componentDatabaseDemo) load() {
	iroutes := router.GetIRoutes("examples/component")
	iroutes.GET("database/test1", d.componentDatabaseDemoApiHandler1)
	iroutes.GET("database/test2", d.componentDatabaseDemoApiHandler2)
}

// 组件测试：database
// @Tags component
// @Summary 组件测试：database(库表初始化)
// @Produce  application/json
// @Success 200 {object} restful.Response{data=map[string]interface{},msg=string} "组件测试：database(库表初始化)"
// @Router /examples/component/database/test1 [get]
func (cdd componentDatabaseDemo) componentDatabaseDemoApiHandler1(c *gin.Context) {
	if nil == database.GetConnection() {
		return
	}
	database.CreateTables(GinOriginDemoModel1{}, GinOriginDemoModel2{}, GinOriginDemoModel3{})
	restful.Success.WithMessage(c, "样例接口1")
}

var (
	METADATE_DEMO1 []GinOriginDemoModel1 = []GinOriginDemoModel1{
		GinOriginDemoModel1{Name: "ginorigin1"},
	}
	METADATE_DEMO2 []GinOriginDemoModel2 = []GinOriginDemoModel2{
		GinOriginDemoModel2{
			BaseModel: database.BaseModel{ // golang中可以使用结构体嵌套，使用嵌套时，如果要新建实例，需要声明源结构体
				CreatedAt: sql.NullTime{Time: time.Now(), Valid: true},
			},
		},
	}
	METADATE_DEMO3 []GinOriginDemoModel3 = []GinOriginDemoModel3{
		GinOriginDemoModel3{
			GinOriginDemoModel1: GinOriginDemoModel1{
				Name: "ginorigin1",
			},
		},
		GinOriginDemoModel3{
			GinOriginDemoModel1: GinOriginDemoModel1{Name: "ginorigin2"},
			GinOriginDemoModel2: GinOriginDemoModel2{
				BaseModel: database.BaseModel{ // 多重嵌套时，需要逐级声明
					CreatedAt: sql.NullTime{Time: time.Now(), Valid: true},
				},
			},
		},
	}
)

// 组件测试：database
// @Tags component
// @Summary 组件测试：database(数据导入)
// @Produce  application/json
// @Success 200 {object} restful.Response{data=map[string]interface{},msg=string} "组件测试：database(数据导入)"
// @Router /examples/component/database/test1 [get]
func (cdd componentDatabaseDemo) componentDatabaseDemoApiHandler2(c *gin.Context) {
	d := &GinOriginDemoModel1{}
	err := database.GetConnection().Model(d).Where("name = ?", "ginorigin1").First(&d).Error
	// err := database.GetConnection().Exec("select * from gin_origin_demo_model1 where name = ?", "ginorigin1").First(&d).Error
	zap.LOGGER.Debug("d", zap.Any("d", d))
	if nil == err && nil != d {
		restful.Success.WithMessage(c, "数据库已有数据")
		return
	} else {
		zap.LOGGER.Info("数据库没有数据，准备进行数据导入")
	}
	// database.Connection.Create(&METADATE_DEMO1) // gorm.Create传入数组时，理默认开启事务进行批处理
	// database.Connection.Create(&METADATE_DEMO2) // 但是，如果连续多个Create，则无法让后续Create的异常触发前面Create的事务
	// database.Connection.Create(&METADATE_DEMO3) // 因此，可以使用下面的方法，手动开启事务，当然，目前暂时没有向java的spring中的@Transction一样的业务级事务控制
	// 事务处理
	// 插入数据，可以是数组，gorm可以根据数组类型，比如GinOriginDemoModel，获取到对应的表（根据模型的TableName()函数），而后批量插入数据
	// 注意：gorm的Create参数需加引用
	if err := database.Transaction(func(tx *gorm.DB) error {
		if err := tx.Create(&METADATE_DEMO1).Error; nil != err {
			return err
		}
		if err := tx.Create(&METADATE_DEMO2).Error; nil != err {
			return err
		}
		if err := tx.Create(&METADATE_DEMO3).Error; nil != err {
			return err
		}
		return nil
	}); err != nil { // 事务异常业务处理
		restful.Failed.WithError(c, err)
		return
	}
	restful.Success.WithMessage(c, "样例接口1")
}
